#include "SceneHierarchyPanel.h"

#include <glm/gtc/type_ptr.hpp>

namespace Hazal
{
    CSceneHierarchyPanel::CSceneHierarchyPanel(const Ref<CScene>& rScene)
        : m_pContext(rScene)
    {
    }

    void CSceneHierarchyPanel::SetContext(const Ref<CScene>& rScene)
    {
        m_pContext = rScene;
		m_selectedEntity = {};
    }

    void CSceneHierarchyPanel::OnImGuiRender()
    {
        HZ_ASSERT(nullptr != m_pContext, "CSceneHierarchyPanel::m_pContext is nullptr!");

        if (ImGui::Begin("Scene Hierarchy"))
        {
            m_pContext->m_registry.each([&](auto& entityId) 
            {
                CEntity entity = { entityId, m_pContext.get() };
                DrawEntiyNode(entity);
            });

			if (ImGui::IsMouseDown(0) && ImGui::IsWindowHovered())
			{
				m_selectedEntity = {  };
			}

			/// 创建窗口上下文菜单	, ImGuiPopupFlags_NoOpenOverItems 表示只在空白处右键生效
			if (ImGui::BeginPopupContextWindow(0, ImGuiPopupFlags_MouseButtonRight | ImGuiPopupFlags_NoOpenOverItems))
			{
				if (ImGui::MenuItem("Create empty entity"))
				{
					m_pContext->CreateEntity("Empty entity");
				}

				ImGui::EndPopup();
			}

            ImGui::End();
        }

        if (ImGui::Begin("Properties"))
        {
            if (m_selectedEntity)
            {
                DrawComponents(m_selectedEntity);
            }

            ImGui::End();
		}
	}

	CEntity CSceneHierarchyPanel::GetSelectedEntity()
	{
		return m_selectedEntity;
	}

	void CSceneHierarchyPanel::SetSelectedEntity(CEntity& entity)
	{
		m_selectedEntity = entity;
	}

	void CSceneHierarchyPanel::DrawEntiyNode(CEntity& entity)
	{
		auto& tag = entity.GetComponent<STagComponent>().m_strTag;

		ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | (m_selectedEntity == entity ? ImGuiTreeNodeFlags_Selected : 0);
		flags |= ImGuiTreeNodeFlags_SpanAvailWidth;	///< 被选中item高亮显示横跨一整行而非字体所占长度

        if (ImGui::TreeNodeEx((void*)(uint32_t)entity, flags, tag.c_str()))
        {
			if (ImGui::IsItemClicked())
			{
				m_selectedEntity = entity;
			}

			if (ImGui::BeginPopupContextItem())
			{

				if (ImGui::MenuItem("Delete entity"))
				{
					if (entity == m_selectedEntity)
					{
						m_selectedEntity = {};
					}
					m_pContext->DestroyEntity(entity);
				}

				ImGui::EndPopup();
			}

            ImGui::TreePop();   // Must need pop by end.
        }
        
	}

	/// <summary>
	/// TODO: Draw imgui vec3 controller
	/// </summary>
	static void DrawVec3Control(const std::string& strLabel, glm::vec3& vecVals, float fResetVal = 0.0f, float fColWidth = 80.0f)
	{
		ImGui::PushID(strLabel.c_str());	/// 为当前绘制的所有控件指定id, 防止因重名导致的问题

		/// 设置字体为粗体(在ImGuiLayer初始化中添加)
		auto& font = ImGui::GetIO().Fonts->Fonts[0];

		/// 第一列, 字段描述信息
		ImGui::Columns(2);	/// 全局设置, 绘制完成后需要更改为columns 1
		ImGui::SetColumnWidth(0, fColWidth);
		ImGui::Text(strLabel.c_str());

		/// 第二列, 字段内容
		ImGui::NextColumn();
		ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
		ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{ 0.0f, 0.0f });	// 每个item之间的距离

		/// 计算button大小
		float fLinkHeight = GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f;
		ImVec2 vecButtonSize = { fLinkHeight, fLinkHeight };

		/// 修改按钮颜色
		ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.1f, 0.15f, 1.0f));
		ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.9f, 0.2f, 0.2f, 1.0f));
		ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.8f, 0.1f, 0.15f, 1.0f));
		{
			ImGui::PushFont(font);
			if (ImGui::Button("X", vecButtonSize))
			{
				vecVals.x = fResetVal;
			}
			ImGui::PopFont();

			ImGui::SameLine();
			ImGui::DragFloat("##X", &vecVals.x, 0.1f, 0.0f, 0.0f, "%.2f");	// ##加字符串时,ImGui界面不显示字体, 应该只做label标识用
			ImGui::PopItemWidth();
		}
		ImGui::PopStyleColor();
		ImGui::PopStyleColor();
		ImGui::PopStyleColor();

		ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.7f, 0.2f, 1.0f));
		ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.8f, 0.3f, 1.0f));
		ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.2f, 0.7f, 0.2f, 1.0f));
		{
			ImGui::SameLine();
			ImGui::PushFont(font);
			if (ImGui::Button("Y", vecButtonSize))
			{
				vecVals.y = fResetVal;
			}
			ImGui::PopFont();

			ImGui::SameLine();
			ImGui::DragFloat("##Y", &vecVals.y, 0.1f, 0.0f, 0.0f, "%.2f");
			ImGui::PopItemWidth();
		}
		ImGui::PopStyleColor();
		ImGui::PopStyleColor();
		ImGui::PopStyleColor();

		ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.1f, 0.25f, 0.8f, 1.0f));
		ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.2f, 0.35f, 0.9f, 1.0f));
		ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.1f, 0.25f, 0.8f, 1.0f));
		{
			ImGui::SameLine();
			ImGui::PushFont(font);
			if (ImGui::Button("Z", vecButtonSize))
			{
				vecVals.z = fResetVal;
			}
			ImGui::PopFont();

			ImGui::SameLine();
			ImGui::DragFloat("##Z", &vecVals.z, 0.1f, 0.0f, 0.0f, "%.2f");
			ImGui::PopItemWidth();
		}
		ImGui::PopStyleColor();
		ImGui::PopStyleColor();
		ImGui::PopStyleColor();

		ImGui::PopStyleVar();

		ImGui::Columns(1);	/// 全局设置, 修改列数为默认 1 columns

		ImGui::PopID();

	}

    void CSceneHierarchyPanel::DrawComponents(CEntity& entity)
    {
        if (entity.HasComponent<STagComponent>())
        {
            auto& tag = entity.GetComponent<STagComponent>().m_strTag;

            char aBuffer[256];
            memset(aBuffer, 0, sizeof(aBuffer));
            strcpy_s(aBuffer, sizeof(aBuffer), tag.c_str());
            if (ImGui::InputText("##Tag", aBuffer, sizeof(aBuffer)))
            {
                tag = std::string(aBuffer);
            }
		}

		ImGui::SameLine();
		ImGui::PushItemWidth(-1);
		if (ImGui::Button("AddComponent"))
		{
			ImGui::OpenPopup("AddComponent");
		}

		/// BeginPopup的str_id需与OpenPopup的str_id保持一致
		if (ImGui::BeginPopup("AddComponent"))
		{
			if (!m_selectedEntity.HasComponent<SCameraComponent>())
			{
				if (ImGui::MenuItem("Camera"))
				{
					m_selectedEntity.AddComponent<SCameraComponent>();
					ImGui::CloseCurrentPopup();
				}
			}

			if (!m_selectedEntity.HasComponent<SSpriteRendererComponent>())
			{
				if (ImGui::MenuItem("Sprite Renderer"))
				{
					m_selectedEntity.AddComponent<SSpriteRendererComponent>();
					ImGui::CloseCurrentPopup();
				}
			}

			if (!m_selectedEntity.HasComponent<SCircleRendererComponent>())
			{
				if (ImGui::MenuItem("Circle Renderer"))
				{
					m_selectedEntity.AddComponent<SCircleRendererComponent>();
					ImGui::CloseCurrentPopup();
				}
			}

			if (!m_selectedEntity.HasComponent<SRigidBody2DComponent>())
			{
				if (ImGui::MenuItem("RigidBody 2D"))
				{
					m_selectedEntity.AddComponent<SRigidBody2DComponent>();
					ImGui::CloseCurrentPopup();
				}
			}

			if (!m_selectedEntity.HasComponent<SCollider2DComponent>())
			{
				if (ImGui::MenuItem("Box Collider 2D"))
				{
					m_selectedEntity.AddComponent<SCollider2DComponent>();
					ImGui::CloseCurrentPopup();
				}
			}

			ImGui::EndPopup();
		}
		ImGui::PopItemWidth();

        if (entity.HasComponent<STransformComponent>())
        {
            DrawComponent<STransformComponent>("Transform", entity, [&]()
                {
                    auto& transformComponent = entity.GetComponent<STransformComponent>();

					DrawVec3Control("Position", transformComponent.m_vecTranslation);

					glm::vec3 vecRotation = glm::degrees(transformComponent.m_vecRotation);
					DrawVec3Control("Rotate", vecRotation);
					transformComponent.m_vecRotation = glm::radians(vecRotation);

					DrawVec3Control("Scale", transformComponent.m_vecScale, 1.0f);
				});
        }

        if (entity.HasComponent<SSpriteRendererComponent>())
        {
            DrawComponent<SSpriteRendererComponent>("Sprite color", entity, [&]()
                {
					auto& spriteComponent = entity.GetComponent<SSpriteRendererComponent>();
					/// Color
					ImGui::ColorEdit4("Square color", glm::value_ptr(spriteComponent.m_vecColor));	

					/// Texture
					ImGui::Button("Texture", {100.0f, 0.0f});

					/// Drop traget. Drop texture id to this component.
					if (ImGui::BeginDragDropTarget())
					{
						const ImGuiPayload* pPayload = ImGui::AcceptDragDropPayload("CONTENT_BROWSER_ITEM");
						if (nullptr != pPayload)
						{
							const wchar_t* wcPath = (const wchar_t*)pPayload->Data;
							std::filesystem::path texturePath = wcPath;

							spriteComponent.m_texture = CTexture2D::Create(texturePath.string());
						}
						ImGui::EndDragDropTarget();
					}

					/// Tiling factor of texture
					ImGui::DragFloat("Tiling factor", &spriteComponent.m_fTilingfFactor, 1.0f, 0.0f, 100.0f);	

                });
        }

		if (entity.HasComponent<SCircleRendererComponent>())
		{
			DrawComponent<SCircleRendererComponent>("Cicle color", entity, [&]()
				{
					auto& spriteComponent = entity.GetComponent<SCircleRendererComponent>();
					/// Color
					ImGui::ColorEdit4("Circle color", glm::value_ptr(spriteComponent.m_vecColor));

					/// Thickness
					ImGui::DragFloat("Thickness", &spriteComponent.m_fThickness, 0.025f, 0.0f, 1.0f);

					/// Fade
					ImGui::DragFloat("Fade", &spriteComponent.m_fFade, 0.00025f, 0.0f, 1.0f);
				});
		}

        if (entity.HasComponent<SCameraComponent>())
        {
            DrawComponent<SCameraComponent>("Camera", entity, [&]()
                {
					auto& cameraComponent = entity.GetComponent<SCameraComponent>();
					auto& camera = cameraComponent.m_Camera;

					bool bPrimary = cameraComponent.m_bPrimary;
					if (ImGui::Checkbox("Primary camera", &bPrimary))
					{
						cameraComponent.m_bPrimary = bPrimary;
					}

					bool bFixed = cameraComponent.m_bFixedAspectRadio;
					if (ImGui::Checkbox("Fixed aspect radio", &bFixed))
					{
						cameraComponent.m_bFixedAspectRadio = bFixed;
					}

					const char* acProjectionTypeStrings[] = { "Perspective", "Orthographic" };
					const char* cCurrentProjectionTypeString = acProjectionTypeStrings[(int)camera.GetProjectionType()];

					if (ImGui::BeginCombo("Projection", cCurrentProjectionTypeString))
					{
						for (int i = 0; i < 2; ++i)
						{
							bool bIsSelected = cCurrentProjectionTypeString == acProjectionTypeStrings[i];
							if (ImGui::Selectable(acProjectionTypeStrings[i], bIsSelected))
							{
								cCurrentProjectionTypeString = acProjectionTypeStrings[i];
								camera.SetProjectionType(i);
							}

							if (bIsSelected)
							{
								ImGui::SetItemDefaultFocus();
							}
						}

						ImGui::EndCombo();
					}

					if (CSceneCamera::ProjectionType::Perspective == camera.GetProjectionType())
					{
						float fVerticalFOV = glm::degrees(camera.GetPerspectiveVerticalFOV());
						if (ImGui::DragFloat("Vertical FOV", &fVerticalFOV))
						{
							camera.SetPerspectiveVerticalFOV(glm::radians(fVerticalFOV));
						}

						float fNearClip = camera.GetPerspectiveNearClip();
						if (ImGui::DragFloat("NearClip", &fNearClip))
						{
							camera.SetPerspectiveNearClip(fNearClip);
						}

						float fFarClip = camera.GetPerspectiveFarClip();
						if (ImGui::DragFloat("FarClip", &fFarClip))
						{
							camera.SetPerspectiveFarClip(fFarClip);
						}
					}
					else if (camera.GetProjectionType() == CSceneCamera::ProjectionType::Orthographic)
					{
						float fZoomLevel = camera.GetOrthographicSize();
						if (ImGui::DragFloat("Size", &fZoomLevel))
						{
							camera.SetOrthographicSize(fZoomLevel);
						}

						float fNearClip = camera.GetOrthographicNearClip();
						if (ImGui::DragFloat("NearClip", &fNearClip))
						{
							camera.SetOrthographicNearClip(fNearClip);
						}

						float fFarClip = camera.GetOrthographicFarClip();
						if (ImGui::DragFloat("FarClip", &fFarClip))
						{
							camera.SetOrthographicFarClip(fFarClip);
						}
					}
					else
					{
						// TODO
					}
                });
        }

		if (entity.HasComponent<SRigidBody2DComponent>())
		{
			DrawComponent<SRigidBody2DComponent>("RigidBody 2D", entity, [&]()
				{
					auto& rigidComponent = entity.GetComponent<SRigidBody2DComponent>();

					const char* aBodyTypeStrings[] = {"Static", "Dynamic", "kinematic"};
					const char* cCurBodyTypeString = aBodyTypeStrings[(int)rigidComponent.m_eBodyType];

					/// Body type
					if (ImGui::BeginCombo("Body type", cCurBodyTypeString))
					{
						for (size_t i = 0; i < 3; ++i)
						{
							bool bSelected = (cCurBodyTypeString == aBodyTypeStrings[i]);
							if (ImGui::Selectable(aBodyTypeStrings[i], bSelected))
							{
								cCurBodyTypeString = aBodyTypeStrings[i];
								rigidComponent.m_eBodyType = (SRigidBody2DComponent::EBodyType)i;
							}

							if (bSelected)
							{
								ImGui::SetItemDefaultFocus();
							}
						}

						ImGui::EndCombo();
					}

					/// Rotation
					ImGui::Checkbox("Fixed rotation", &rigidComponent.m_bFixedRotation);

				});
		}

		if (entity.HasComponent<SCollider2DComponent>())
		{
			DrawComponent<SCollider2DComponent>("Collider 2D", entity, [&]()
				{
					auto& colliderComponent = entity.GetComponent<SCollider2DComponent>();

					ImGui::DragFloat2("Offset", glm::value_ptr(colliderComponent.m_v2Offset));
					ImGui::DragFloat2("Size", glm::value_ptr(colliderComponent.m_v2Size));

					ImGui::DragFloat("Density", &colliderComponent.m_fDensity, 0.01f, 0.0f, 1.0f);
					ImGui::DragFloat("Friction", &colliderComponent.m_fFriction, 0.01f, 0.0f, 1.0f);

					ImGui::DragFloat("Restitution", &colliderComponent.m_fRestitution, 0.01f, 0.0f, 1.0f);
					ImGui::DragFloat("Restitution Threshold", &colliderComponent.m_fRestitutionThreshold, 0.01f, 0.0f);
				});
		}
    }
}